/*
	       File: DirectoryProcessor.cs
	Create Date: 2007-08-12
	    Version:

	Description:


	 Change log:


*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

using GuerillaProgrammer.Components.Logging;
using GuerillaProgrammer.FileProcessor.Settings;

namespace GuerillaProgrammer.FileProcessor
{
    public class DirectoryProcessor
    {
        #region Private member fields
        private Configuration _Configuration;
        private ConfigurationDirectory _Directory;
        private List<ConfigurationFileType> _FileTypes;
        private IWorkItemProcessor _WorkItemProcessor;
        #endregion

        #region Constructors and cleanup methods
        public DirectoryProcessor(Configuration configuration, ConfigurationDirectory directory, List<ConfigurationFileType> fileTypes, IWorkItemProcessor workItemProcessor)
        {
            _Configuration = configuration;
            _Directory = directory;
            _FileTypes = fileTypes;
            _WorkItemProcessor = workItemProcessor;
        }
        #endregion

        #region Private implementation methods
        private ConfigurationFileType GetFileType(string fileTypeID)
        {
            Logger.LogEnter();
            foreach (ConfigurationFileType fileType in _FileTypes)
            {
                if (fileTypeID == fileType.ID)
                {
                    return fileType;
                }
            }
            Logger.LogLeave();
            return null;
        }
        private void ArchiveFile(WorkItem workItem)
        {
            string archiveFileName = string.Format("{0}_{1}_{2}_{3}.{4}"
                                                    ,Path.GetFileNameWithoutExtension(workItem.Filename)
                                                    ,workItem.FileTypeID
                                                    ,workItem.DirectoryID
                                                    ,DateTime.Now.ToString("yyyy_MM_dd_hh_mm_ss")
                                                    ,Path.GetExtension(workItem.Filename));
            string archivePath = Path.Combine(_Configuration.Services.ArchiveDirectory, archiveFileName);
            File.Copy(workItem.Filename, archivePath);
        }
        private void MoveToWorkingDirectory(WorkItem workItem)
        {
            string workFileName = string.Format("{0}_{1}{2}",Path.GetFileNameWithoutExtension(workItem.Filename), Guid.NewGuid().ToString(), Path.GetExtension(workItem.Filename));
            string workingDirectory = Path.Combine(_Configuration.Services.WorkingDirectory, workFileName);

            File.Copy(workItem.Filename, workingDirectory);
            File.Delete(workItem.Filename);
            workItem.OriginalName = workItem.Filename;
            workItem.Filename = workingDirectory;
        }
        private void QueryDirectoryForFileType(ConfigurationDirectory directory, ConfigurationFileType fileType)
        {
            Logger.LogEnter();
            string[] files = Directory.GetFiles(directory.Path, fileType.FilePattern);
            Logger.LogInfo("Files", "Adding {0} files to the collection", files.Length);

            foreach (string file in files)
            {
                //make sure the file isn't open before adding it to the work queue
                try
                {
                    //this is the lamest way possible to do it, but it is quick and dirty for now
                    //change to use the C api so I can check for file handles = it is quicker.
                    //Stream fileStream = File.Open(file, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
                    //fileStream.Close();

                    WorkItem workItem = new WorkItem(file, fileType.ID, directory.ID);

                    ArchiveFile(workItem);
                    MoveToWorkingDirectory(workItem);
                    
                    DoAddWorkItem(workItem);
                }
                catch(Exception exc)
                {
                    Logger.LogInfo("File open", "The file ({0}) was open so it won't be processed.\nError: {1}\n", file,exc.Message);
                }
            }
            Logger.LogLeave();
        }
        private void DoAddWorkItem(WorkItem workItem)
        {
            if (null != _WorkItemProcessor)
            {
                _WorkItemProcessor.ProcessWorkItem(workItem);
            }
            else
            {
                throw new NullReferenceException("Work item processor must be set.");
            }
        }
        #endregion

        #region Public interface
        public void ProcessDirectory(object stateInfo)
        {
            Logger.LogEnter();
            foreach (string fileTypeID in _Directory.DirectoryFileTypes)
            {
                ConfigurationFileType fileType = GetFileType(fileTypeID);
                if (null == fileType)
                {
                    //Log the fact that we can't find this
                    continue;
                }
                QueryDirectoryForFileType(_Directory, fileType);
            }
            Logger.LogLeave();
        }
        #endregion
    }
}
